home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / mac / DirectX SDK / DXSDK / samples / Multimedia / Direct3D / Pick / pick.cpp < prev    next >
C/C++ Source or Header  |  2001-10-31  |  26KB  |  719 lines

  1. //-----------------------------------------------------------------------------
  2. // File: Pick.cpp
  3. //
  4. // Desc: Example code showing how to do picking in D3D.
  5. //
  6. // Copyright (c) 1997-2001 Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #define STRICT
  9. #include <math.h>
  10. #include <stdio.h>
  11. #include <D3DX8.h>
  12. #include "D3DApp.h"
  13. #include "D3DFont.h"
  14. #include "D3DFile.h"
  15. #include "D3DUtil.h"
  16. #include "DXUtil.h"
  17. #include "Resource.h"
  18.  
  19.  
  20. struct D3DVERTEX
  21. {
  22.     D3DXVECTOR3 p;
  23.     D3DXVECTOR3 n;
  24.     FLOAT       tu, tv;
  25. };
  26.  
  27. #define D3DFVF_VERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)
  28.  
  29.  
  30. struct INTERSECTION
  31. {
  32.     DWORD dwFace;                 // mesh face that was intersected
  33.     FLOAT fBary1, fBary2;         // barycentric coords of intersection
  34.     FLOAT fDist;                  // distance from ray origin to intersection
  35.     FLOAT tu, tv;                 // texture coords of intersection
  36. };
  37.  
  38. // For simplicity's sake, we limit the number of simultaneously intersected 
  39. // triangles to 16
  40. #define MAX_INTERSECTIONS 16
  41.  
  42.  
  43. //-----------------------------------------------------------------------------
  44. // Name: class CMyD3DApplication
  45. // Desc: Application class. The base class (CD3DApplication) provides the 
  46. //       generic functionality needed in all Direct3D samples. CMyD3DApplication 
  47. //       adds functionality specific to this sample program.
  48. //-----------------------------------------------------------------------------
  49. class CMyD3DApplication : public CD3DApplication
  50. {
  51.     CD3DFont*   m_pFont;                      // Font for drawing text
  52.     CD3DFont*   m_pFontSmall;                 // Font for drawing text
  53.     CD3DMesh*   m_pObject;                    // Object to render
  54.     DWORD       m_dwNumIntersections;         // Number of faces intersected
  55.     INTERSECTION m_IntersectionArray[MAX_INTERSECTIONS]; // Intersection info
  56.     LPDIRECT3DVERTEXBUFFER8 m_pVB;            // VB for picked triangles
  57.     BOOL        m_bShowHelp;                  // Whether to show help
  58.     BOOL        m_bUseD3DX;                   // Whether to use D3DXIntersect
  59.     BOOL        m_bClosestOnly;               // Whether to just get the closest intersection
  60.  
  61.     // Internal member functions
  62.     HRESULT Pick();
  63.     BOOL    IntersectTriangle( const D3DXVECTOR3& orig, const D3DXVECTOR3& dir,
  64.                                D3DXVECTOR3& v0, D3DXVECTOR3& v1, D3DXVECTOR3& v2,
  65.                                FLOAT* t, FLOAT* u, FLOAT* v );
  66.     HRESULT ConfirmDevice( D3DCAPS8*, DWORD, D3DFORMAT );
  67.  
  68. protected:
  69.     HRESULT OneTimeSceneInit();
  70.     HRESULT InitDeviceObjects();
  71.     HRESULT RestoreDeviceObjects();
  72.     HRESULT InvalidateDeviceObjects();
  73.     HRESULT DeleteDeviceObjects();
  74.     HRESULT Render();
  75.     HRESULT FrameMove();
  76.     HRESULT FinalCleanup();
  77.  
  78. public:
  79.     LRESULT MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
  80.     CMyD3DApplication();
  81. };
  82.  
  83.  
  84.  
  85.  
  86. //-----------------------------------------------------------------------------
  87. // Name: WinMain()
  88. // Desc: Entry point to the program. Initializes everything, and goes into a
  89. //       message-processing loop. Idle time is used to render the scene.
  90. //-----------------------------------------------------------------------------
  91. INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
  92. {
  93.     CMyD3DApplication d3dApp;
  94.  
  95.     if( FAILED( d3dApp.Create( hInst ) ) )
  96.         return 0;
  97.  
  98.     return d3dApp.Run();
  99. }
  100.  
  101.  
  102.  
  103.  
  104. //-----------------------------------------------------------------------------
  105. // Name: CMyD3DApplication()
  106. // Desc: Application constructor. Sets attributes for the app.
  107. //-----------------------------------------------------------------------------
  108. CMyD3DApplication::CMyD3DApplication()
  109. {
  110.     m_strWindowTitle    = _T("Pick: D3D Picking Sample");
  111.     m_bUseDepthBuffer   = TRUE;
  112.     m_bShowCursorWhenFullscreen = TRUE;
  113.  
  114.     m_pFont         = new CD3DFont( _T("Arial"), 12, D3DFONT_BOLD );
  115.     m_pFontSmall    = new CD3DFont( _T("Arial"), 9, D3DFONT_BOLD );
  116.     m_pObject       = new CD3DMesh();
  117.     m_dwNumIntersections = 0;
  118.     m_pVB           = NULL;
  119.     m_bShowHelp     = FALSE;
  120.     m_bUseD3DX      = TRUE;
  121.     m_bClosestOnly  = FALSE;
  122. }
  123.  
  124.  
  125.  
  126.  
  127. //-----------------------------------------------------------------------------
  128. // Name: OneTimeSceneInit()
  129. // Desc: Called during initial app startup, this function performs all the
  130. //       permanent initialization.
  131. //-----------------------------------------------------------------------------
  132. HRESULT CMyD3DApplication::OneTimeSceneInit()
  133. {
  134.     return S_OK;
  135. }
  136.  
  137.  
  138.  
  139.  
  140. //-----------------------------------------------------------------------------
  141. // Name: Pick()
  142. // Desc: Checks if mouse point hits geometry
  143. //       the scene.
  144. //-----------------------------------------------------------------------------
  145. HRESULT CMyD3DApplication::Pick()
  146. {
  147.     HRESULT hr;
  148.     D3DXVECTOR3 vPickRayDir;
  149.     D3DXVECTOR3 vPickRayOrig;
  150.  
  151.     m_dwNumIntersections = 0L;
  152.  
  153.     // Get the pick ray from the mouse position
  154.     if( GetCapture() )
  155.     {
  156.         D3DXMATRIX matProj;
  157.         m_pd3dDevice->GetTransform( D3DTS_PROJECTION, &matProj );
  158.  
  159.         POINT ptCursor;
  160.         GetCursorPos( &ptCursor );
  161.         ScreenToClient( m_hWnd, &ptCursor );
  162.  
  163.         // Compute the vector of the pick ray in screen space
  164.         D3DXVECTOR3 v;
  165.         v.x =  ( ( ( 2.0f * ptCursor.x ) / m_d3dsdBackBuffer.Width  ) - 1 ) / matProj._11;
  166.         v.y = -( ( ( 2.0f * ptCursor.y ) / m_d3dsdBackBuffer.Height ) - 1 ) / matProj._22;
  167.         v.z =  1.0f;
  168.  
  169.         // Get the inverse view matrix
  170.         D3DXMATRIX matView, m;
  171.         m_pd3dDevice->GetTransform( D3DTS_VIEW, &matView );
  172.         D3DXMatrixInverse( &m, NULL, &matView );
  173.  
  174.         // Transform the screen space pick ray into 3D space
  175.         vPickRayDir.x  = v.x*m._11 + v.y*m._21 + v.z*m._31;
  176.         vPickRayDir.y  = v.x*m._12 + v.y*m._22 + v.z*m._32;
  177.         vPickRayDir.z  = v.x*m._13 + v.y*m._23 + v.z*m._33;
  178.         vPickRayOrig.x = m._41;
  179.         vPickRayOrig.y = m._42;
  180.         vPickRayOrig.z = m._43;
  181.     }
  182.  
  183.     // Get the picked triangle
  184.     if( GetCapture() )
  185.     {
  186.         LPD3DXBASEMESH          pMesh = m_pObject->GetLocalMesh();
  187.         LPDIRECT3DVERTEXBUFFER8 pVB;
  188.         LPDIRECT3DINDEXBUFFER8  pIB;
  189.  
  190.         pMesh->GetVertexBuffer( &pVB );
  191.         pMesh->GetIndexBuffer( &pIB );
  192.  
  193.         WORD*      pIndices;
  194.         D3DVERTEX*    pVertices;
  195.  
  196.         pIB->Lock( 0,0,(BYTE**)&pIndices, 0 );
  197.         pVB->Lock( 0,0,(BYTE**)&pVertices, 0 );
  198.  
  199.         if( m_bUseD3DX )
  200.         {
  201.             // When calling D3DXIntersect, one can get just the closest intersection and not
  202.             // need to work with a D3DXBUFFER.  Or, to get all intersections between the ray and 
  203.             // the mesh, one can use a D3DXBUFFER to receive all intersections.  We show both
  204.             // methods.
  205.             if( m_bClosestOnly )
  206.             {
  207.                 // Collect only the closest intersection
  208.                 BOOL bHit;
  209.                 DWORD dwFace;
  210.                 FLOAT fBary1, fBary2, fDist;
  211.                 D3DXIntersect(pMesh, &vPickRayOrig, &vPickRayDir, &bHit, &dwFace, &fBary1, &fBary2, &fDist, 
  212.                     NULL, NULL);
  213.                 if( bHit )
  214.                 {
  215.                     m_dwNumIntersections = 1;
  216.                     m_IntersectionArray[0].dwFace = dwFace;
  217.                     m_IntersectionArray[0].fBary1 = fBary1;
  218.                     m_IntersectionArray[0].fBary2 = fBary2;
  219.                     m_IntersectionArray[0].fDist = fDist;
  220.                 }
  221.                 else
  222.                 {
  223.                     m_dwNumIntersections = 0;
  224.                 }
  225.             }
  226.             else 
  227.             {
  228.                 // Collect all intersections
  229.                 BOOL bHit;
  230.                 LPD3DXBUFFER pBuffer = NULL;
  231.                 D3DXINTERSECTINFO* pIntersectInfoArray;
  232.                 if( FAILED( hr = D3DXIntersect(pMesh, &vPickRayOrig, &vPickRayDir, &bHit, NULL, NULL, NULL, NULL, 
  233.                     &pBuffer, &m_dwNumIntersections) ) )
  234.                 {
  235.                     return hr;
  236.                 }
  237.                 if( m_dwNumIntersections > 0 )
  238.                 {
  239.                     pIntersectInfoArray = (D3DXINTERSECTINFO*)pBuffer->GetBufferPointer();
  240.                     if( m_dwNumIntersections > MAX_INTERSECTIONS )
  241.                         m_dwNumIntersections = MAX_INTERSECTIONS;
  242.                     for( DWORD iIntersection = 0; iIntersection < m_dwNumIntersections; iIntersection++ )
  243.                     {
  244.                         m_IntersectionArray[iIntersection].dwFace = pIntersectInfoArray[iIntersection].FaceIndex;
  245.                         m_IntersectionArray[iIntersection].fBary1 = pIntersectInfoArray[iIntersection].U;
  246.                         m_IntersectionArray[iIntersection].fBary2 = pIntersectInfoArray[iIntersection].V;
  247.                         m_IntersectionArray[iIntersection].fDist = pIntersectInfoArray[iIntersection].Dist;
  248.                     }
  249.                 }
  250.             }
  251.  
  252.         }
  253.         else
  254.         {
  255.             // Not using D3DX
  256.             DWORD dwNumFaces = m_pObject->GetLocalMesh()->GetNumFaces();
  257.             FLOAT fBary1, fBary2;
  258.             FLOAT fDist;
  259.             for( DWORD i=0; i<dwNumFaces; i++ )
  260.             {
  261.                 D3DXVECTOR3 v0 = pVertices[pIndices[3*i+0]].p;
  262.                 D3DXVECTOR3 v1 = pVertices[pIndices[3*i+1]].p;
  263.                 D3DXVECTOR3 v2 = pVertices[pIndices[3*i+2]].p;
  264.  
  265.                 // Check if the pick ray passes through this point
  266.                 if( IntersectTriangle( vPickRayOrig, vPickRayDir, v0, v1, v2,
  267.                                        &fDist, &fBary1, &fBary2 ) )
  268.                 {
  269.                     if( !m_bClosestOnly || m_dwNumIntersections == 0 || fDist < m_IntersectionArray[0].fDist )
  270.                     {
  271.                         if( m_bClosestOnly )
  272.                             m_dwNumIntersections = 0;
  273.                         m_IntersectionArray[m_dwNumIntersections].dwFace = i;
  274.                         m_IntersectionArray[m_dwNumIntersections].fBary1 = fBary1;
  275.                         m_IntersectionArray[m_dwNumIntersections].fBary2 = fBary2;
  276.                         m_IntersectionArray[m_dwNumIntersections].fDist = fDist;
  277.                         m_dwNumIntersections++;
  278.                         if( m_dwNumIntersections == MAX_INTERSECTIONS )
  279.                             break;
  280.                     }
  281.                 }
  282.             }
  283.         }
  284.  
  285.         // Now, for each intersection, add a triangle to m_pVB and compute texture coordinates
  286.         if( m_dwNumIntersections > 0 )
  287.         {
  288.             D3DVERTEX* v;
  289.             D3DVERTEX* vThisTri;
  290.             WORD* iThisTri;
  291.             D3DVERTEX  v1, v2, v3;
  292.             INTERSECTION* pIntersection;
  293.  
  294.             m_pVB->Lock( 0, 0, (BYTE**)&v, 0 );
  295.  
  296.             for( DWORD iIntersection = 0; iIntersection < m_dwNumIntersections; iIntersection++ )
  297.             {
  298.                 pIntersection = &m_IntersectionArray[iIntersection];
  299.  
  300.                 vThisTri = &v[iIntersection * 3];
  301.                 iThisTri = &pIndices[3*pIntersection->dwFace];
  302.                 // get vertices hit
  303.                 vThisTri[0] = pVertices[iThisTri[0]];
  304.                 vThisTri[1] = pVertices[iThisTri[1]];
  305.                 vThisTri[2] = pVertices[iThisTri[2]];
  306.  
  307.                 // If all you want is the vertices hit, then you are done.  In this sample, we
  308.                 // want to show how to infer texture coordinates as well, using the BaryCentric
  309.                 // coordinates supplied by D3DXIntersect
  310.                 FLOAT dtu1 = vThisTri[1].tu - vThisTri[0].tu;
  311.                 FLOAT dtu2 = vThisTri[2].tu - vThisTri[0].tu;
  312.                 FLOAT dtv1 = vThisTri[1].tv - vThisTri[0].tv;
  313.                 FLOAT dtv2 = vThisTri[2].tv - vThisTri[0].tv;
  314.                 pIntersection->tu = vThisTri[0].tu + pIntersection->fBary1 * dtu1 + pIntersection->fBary2 * dtu2;
  315.                 pIntersection->tv = vThisTri[0].tv + pIntersection->fBary1 * dtv1 + pIntersection->fBary2 * dtv2;
  316.             }
  317.             m_pVB->Unlock();
  318.         }
  319.  
  320.         pVB->Unlock();
  321.         pIB->Unlock();
  322.  
  323.         pVB->Release();
  324.         pIB->Release();
  325.  
  326.     }
  327.  
  328.  
  329.     return S_OK;
  330. }
  331.  
  332.  
  333.  
  334.  
  335. //-----------------------------------------------------------------------------
  336. // Name: FrameMove()
  337. // Desc: Called once per frame, the call is the entry point for animating
  338. //       the scene.
  339. //-----------------------------------------------------------------------------
  340. HRESULT CMyD3DApplication::FrameMove()
  341. {
  342.     // Rotate the camera about the y-axis
  343.     D3DXVECTOR3 vFromPt   = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  344.     D3DXVECTOR3 vLookatPt = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  345.     D3DXVECTOR3 vUpVec    = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  346.     vFromPt.x = -cosf(m_fTime/3.0f) * 4.0f;
  347.     vFromPt.y = 1.0f;
  348.     vFromPt.z =  sinf(m_fTime/3.0f) * 4.0f;
  349.  
  350.     D3DXMATRIX matView;
  351.     D3DXMatrixLookAtLH( &matView, &vFromPt, &vLookatPt, &vUpVec );
  352.     m_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );
  353.  
  354.     return S_OK;
  355. }
  356.  
  357.  
  358.  
  359.  
  360. //-----------------------------------------------------------------------------
  361. // Name: Render()
  362. // Desc: Called once per frame, the call is the entry point for 3d
  363. //       rendering. This function sets up render states, clears the
  364. //       viewport, and renders the scene.
  365. //-----------------------------------------------------------------------------
  366. HRESULT CMyD3DApplication::Render()
  367. {
  368.     // Set up the cursor
  369.     POINT ptCursor;
  370.     GetCursorPos( &ptCursor );
  371.     ScreenToClient( m_hWnd, &ptCursor );
  372.     m_pd3dDevice->SetCursorPosition( ptCursor.x, ptCursor.y, 0L );
  373.  
  374.     // Check for picked triangles
  375.     Pick();
  376.  
  377.     // Clear the viewport
  378.     m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
  379.                          0x000000ff, 1.0f, 0L );
  380.  
  381.     // Begin the scene
  382.     if( SUCCEEDED( m_pd3dDevice->BeginScene() ) )
  383.     {
  384.         // Set render mode to lit, solid triangles
  385.         m_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
  386.         m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
  387.  
  388.         // If a triangle is picked, draw it
  389.         if( m_dwNumIntersections > 0 )
  390.         {
  391.             // Draw the picked triangle
  392.             m_pd3dDevice->SetVertexShader( D3DFVF_VERTEX );
  393.             m_pd3dDevice->SetStreamSource( 0, m_pVB, sizeof(D3DVERTEX) );
  394.             m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, m_dwNumIntersections );
  395.  
  396.             // Set render mode to unlit, wireframe triangles
  397.             m_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME );
  398.             m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
  399.         }
  400.  
  401.         // Render the mesh
  402.         m_pObject->Render( m_pd3dDevice );
  403.  
  404.         // Output statistics
  405.         m_pFont->DrawText( 2,  0, D3DCOLOR_ARGB(255,255,255,0), m_strFrameStats );
  406.         m_pFont->DrawText( 2, 20, D3DCOLOR_ARGB(255,255,255,0), m_strDeviceStats );
  407.  
  408.         // Output help
  409.         FLOAT yText = 40.0f;
  410.         if( m_bShowHelp )
  411.         {
  412.             m_pFontSmall->DrawText( 2, yText, D3DCOLOR_ARGB(255,255,255,255), _T("F1: Toggle Help") );
  413.             yText += 20.0f;
  414.             m_pFontSmall->DrawText( 2, yText, D3DCOLOR_ARGB(255,255,255,255), _T("F2: Change Device") );
  415.             yText += 20.0f;
  416.             m_pFontSmall->DrawText( 2, yText, D3DCOLOR_ARGB(255,255,255,255), _T("F3: Toggle D3DX Usage") );
  417.             yText += 20.0f;
  418.             m_pFontSmall->DrawText( 2, yText, D3DCOLOR_ARGB(255,255,255,255), _T("F4: Toggle All Hits") );
  419.             yText += 20.0f;
  420.         }
  421.         else
  422.         {
  423.             m_pFontSmall->DrawText( 2, yText, D3DCOLOR_ARGB(255,255,255,255), _T("Press F1 for Help") );
  424.             yText += 20.0f;
  425.         }
  426.  
  427.         // Output info
  428.         m_pFontSmall->DrawText( 2, yText, D3DCOLOR_ARGB(255,255,255,255), m_bUseD3DX ? _T("Using D3DX") : _T("Not Using D3DX") );
  429.         yText += 20.0f;
  430.  
  431.         m_pFontSmall->DrawText( 2, yText, D3DCOLOR_ARGB(255,255,255,255), m_bClosestOnly ? _T("Showing First Hit") : _T("Showing All Hits") );
  432.         yText += 20.0f;
  433.  
  434.         CHAR strBuffer[90];
  435.  
  436.         if( m_dwNumIntersections > 0 )
  437.         {
  438.             for( DWORD iIntersection = 0; iIntersection < m_dwNumIntersections; iIntersection++ )
  439.             {
  440.                 INTERSECTION* pIntersection = &m_IntersectionArray[iIntersection];
  441.                 sprintf( strBuffer, _T("Face=%d, tu=%3.02f, tv=%3.02f"), pIntersection->dwFace, pIntersection->tu, pIntersection->tv );
  442.                 m_pFontSmall->DrawText( 2, yText, D3DCOLOR_ARGB(255,0,255,255), strBuffer );
  443.                 yText += 20;
  444.             }
  445.         }
  446.         else
  447.         {
  448.             sprintf( strBuffer, _T("Use mouse to pick a polygon") );
  449.             m_pFontSmall->DrawText( 2, yText, D3DCOLOR_ARGB(255,0,255,255), strBuffer );
  450.         }
  451.         
  452.  
  453.         // End the scene.
  454.         m_pd3dDevice->EndScene();
  455.     }
  456.  
  457.     return S_OK;
  458. }
  459.  
  460.  
  461.  
  462.  
  463. //-----------------------------------------------------------------------------
  464. // Name: InitDeviceObjects()
  465. // Desc: Initialize scene objects.
  466. //-----------------------------------------------------------------------------
  467. HRESULT CMyD3DApplication::InitDeviceObjects()
  468. {
  469.     // Restore the font
  470.     m_pFont->InitDeviceObjects( m_pd3dDevice );
  471.     m_pFontSmall->InitDeviceObjects( m_pd3dDevice );
  472.  
  473.     if( FAILED( m_pObject->Create( m_pd3dDevice, _T("Tiger.x") ) ) )
  474.         return D3DAPPERR_MEDIANOTFOUND;
  475.     m_pObject->SetFVF( m_pd3dDevice, D3DFVF_VERTEX );
  476.  
  477.     // Create the vertex buffer
  478.     DWORD dwNumVertices = MAX_INTERSECTIONS * 3;
  479.     if( FAILED( m_pd3dDevice->CreateVertexBuffer( dwNumVertices*sizeof(D3DVERTEX),
  480.                                                   D3DUSAGE_WRITEONLY, D3DFVF_VERTEX,
  481.                                                   D3DPOOL_MANAGED, &m_pVB ) ) )
  482.     {
  483.         return E_FAIL;
  484.     }
  485.  
  486.     return S_OK;
  487. }
  488.  
  489.  
  490.  
  491.  
  492. //-----------------------------------------------------------------------------
  493. // Name: RestoreDeviceObjects()
  494. // Desc: Initialize scene objects.
  495. //-----------------------------------------------------------------------------
  496. HRESULT CMyD3DApplication::RestoreDeviceObjects()
  497. {
  498.     m_pFont->RestoreDeviceObjects();
  499.     m_pFontSmall->RestoreDeviceObjects();
  500.  
  501.     // Restore device-memory objects for the mesh
  502.     m_pObject->RestoreDeviceObjects( m_pd3dDevice );
  503.  
  504.     // Set up the textures
  505.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  506.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
  507.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
  508.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
  509.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
  510.  
  511.     // Set miscellaneous render states
  512.     m_pd3dDevice->SetRenderState( D3DRS_DITHERENABLE,   FALSE );
  513.     m_pd3dDevice->SetRenderState( D3DRS_SPECULARENABLE, FALSE );
  514.     m_pd3dDevice->SetRenderState( D3DRS_ZENABLE,        TRUE );
  515.     m_pd3dDevice->SetRenderState( D3DRS_AMBIENT,        0x00444444 );
  516.  
  517.     // Set the world matrix
  518.     D3DXMATRIX matIdentity;
  519.     D3DXMatrixIdentity( &matIdentity );
  520.     m_pd3dDevice->SetTransform( D3DTS_WORLD,  &matIdentity );
  521.  
  522.     // Set the projection matrix
  523.     D3DXMATRIX matProj;
  524.     FLOAT fAspect = ((FLOAT)m_d3dsdBackBuffer.Width) / m_d3dsdBackBuffer.Height;
  525.     D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, fAspect, 1.0f, 100.0f );
  526.     m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
  527.  
  528.     // Setup a material
  529.     D3DMATERIAL8 mtrl;
  530.     D3DUtil_InitMaterial( mtrl, 1.0f, 1.0f, 1.0f, 1.0f );
  531.     m_pd3dDevice->SetMaterial( &mtrl );
  532.  
  533.     // Set up lighting states
  534.     D3DLIGHT8 light;
  535.     D3DUtil_InitLight( light, D3DLIGHT_DIRECTIONAL, 0.1f, -1.0f, 0.1f );
  536.     m_pd3dDevice->SetLight( 0, &light );
  537.     m_pd3dDevice->LightEnable( 0, TRUE );
  538.     m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
  539.  
  540.     return S_OK;
  541. }
  542.  
  543.  
  544.  
  545.  
  546. //-----------------------------------------------------------------------------
  547. // Name: InvalidateDeviceObjects()
  548. // Desc:
  549. //-----------------------------------------------------------------------------
  550. HRESULT CMyD3DApplication::InvalidateDeviceObjects()
  551. {
  552.     m_pFont->InvalidateDeviceObjects();
  553.     m_pFontSmall->InvalidateDeviceObjects();
  554.     m_pObject->InvalidateDeviceObjects();
  555.  
  556.     return S_OK;
  557. }
  558.  
  559.  
  560.  
  561.  
  562. //-----------------------------------------------------------------------------
  563. // Name: DeleteDeviceObjects()
  564. // Desc: Called when the app is exiting, or the device is being changed,
  565. //       this function deletes any device dependent objects.
  566. //-----------------------------------------------------------------------------
  567. HRESULT CMyD3DApplication::DeleteDeviceObjects()
  568. {
  569.     m_pFont->DeleteDeviceObjects();
  570.     m_pFontSmall->DeleteDeviceObjects();
  571.     m_pObject->Destroy();
  572.  
  573.     SAFE_RELEASE( m_pVB );
  574.     return S_OK;
  575. }
  576.  
  577.  
  578.  
  579.  
  580. //-----------------------------------------------------------------------------
  581. // Name: FinalCleanup()
  582. // Desc: Called before the app exits, this function gives the app the chance
  583. //       to cleanup after itself.
  584. //-----------------------------------------------------------------------------
  585. HRESULT CMyD3DApplication::FinalCleanup()
  586. {
  587.     SAFE_DELETE( m_pFont );
  588.     SAFE_DELETE( m_pFontSmall );
  589.  
  590.     return S_OK;
  591. }
  592.  
  593.  
  594.  
  595.  
  596. //-----------------------------------------------------------------------------
  597. // Name: ConfirmDevice()
  598. // Desc: Called during device intialization, this code checks the device
  599. //       for some minimum set of capabilities
  600. //-----------------------------------------------------------------------------
  601. HRESULT CMyD3DApplication::ConfirmDevice( D3DCAPS8* pCaps, DWORD dwBehavior,
  602.                                           D3DFORMAT Format )
  603. {
  604.     if( dwBehavior & D3DCREATE_PUREDEVICE )
  605.         return E_FAIL; // GetTransform doesn't work on PUREDEVICE
  606.  
  607.     // If this is a TnL device, make sure it supports directional lights
  608.     if( (dwBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING ) ||
  609.         (dwBehavior & D3DCREATE_MIXED_VERTEXPROCESSING ) )
  610.     {
  611.         if( !(pCaps->VertexProcessingCaps & D3DVTXPCAPS_DIRECTIONALLIGHTS ) )
  612.             return E_FAIL;
  613.     }
  614.  
  615.     return S_OK;
  616. }
  617.  
  618.  
  619.  
  620.  
  621. //-----------------------------------------------------------------------------
  622. // Name: MsgProc()
  623. // Desc: Overrrides the main WndProc, so the sample can do custom message
  624. //       handling (e.g. processing mouse, keyboard, or menu commands).
  625. //-----------------------------------------------------------------------------
  626. LRESULT CMyD3DApplication::MsgProc( HWND hWnd, UINT msg, WPARAM wParam,
  627.                                     LPARAM lParam )
  628. {
  629.     switch( msg )
  630.     {
  631.         case WM_LBUTTONDOWN:
  632.             // User pressed left mouse button
  633.             SetCapture( hWnd );
  634.             break;
  635.  
  636.         case WM_LBUTTONUP:
  637.             // The user released the left mouse button
  638.             ReleaseCapture();
  639.             break;
  640.  
  641.         case WM_COMMAND:
  642.             if( LOWORD(wParam) == IDM_HELP )
  643.                 m_bShowHelp = !m_bShowHelp;
  644.             if( LOWORD(wParam) == IDM_TOGGLED3DX )
  645.                 m_bUseD3DX = !m_bUseD3DX;
  646.             else if( LOWORD(wParam) == IDM_TOGGLEALLHITS )
  647.                 m_bClosestOnly = !m_bClosestOnly;
  648.             break;
  649.     }
  650.  
  651.     return CD3DApplication::MsgProc( hWnd, msg, wParam, lParam );
  652. }
  653.  
  654.  
  655.  
  656.  
  657. //-----------------------------------------------------------------------------
  658. // Name: IntersectTriangle()
  659. // Desc: Given a ray origin (orig) and direction (dir), and three vertices of
  660. //       of a triangle, this function returns TRUE and the interpolated texture
  661. //       coordinates if the ray intersects the triangle
  662. //-----------------------------------------------------------------------------
  663. BOOL CMyD3DApplication::IntersectTriangle( const D3DXVECTOR3& orig,
  664.                                        const D3DXVECTOR3& dir, D3DXVECTOR3& v0,
  665.                                        D3DXVECTOR3& v1, D3DXVECTOR3& v2,
  666.                                        FLOAT* t, FLOAT* u, FLOAT* v )
  667. {
  668.     // Find vectors for two edges sharing vert0
  669.     D3DXVECTOR3 edge1 = v1 - v0;
  670.     D3DXVECTOR3 edge2 = v2 - v0;
  671.  
  672.     // Begin calculating determinant - also used to calculate U parameter
  673.     D3DXVECTOR3 pvec;
  674.     D3DXVec3Cross( &pvec, &dir, &edge2 );
  675.  
  676.     // If determinant is near zero, ray lies in plane of triangle
  677.     FLOAT det = D3DXVec3Dot( &edge1, &pvec );
  678.  
  679.     D3DXVECTOR3 tvec;
  680.     if( det > 0 )
  681.     {
  682.         tvec = orig - v0;
  683.     }
  684.     else
  685.     {
  686.         tvec = v0 - orig;
  687.         det = -det;
  688.     }
  689.  
  690.     if( det < 0.0001f )
  691.         return FALSE;
  692.  
  693.     // Calculate U parameter and test bounds
  694.     *u = D3DXVec3Dot( &tvec, &pvec );
  695.     if( *u < 0.0f || *u > det )
  696.         return FALSE;
  697.  
  698.     // Prepare to test V parameter
  699.     D3DXVECTOR3 qvec;
  700.     D3DXVec3Cross( &qvec, &tvec, &edge1 );
  701.  
  702.     // Calculate V parameter and test bounds
  703.     *v = D3DXVec3Dot( &dir, &qvec );
  704.     if( *v < 0.0f || *u + *v > det )
  705.         return FALSE;
  706.  
  707.     // Calculate t, scale parameters, ray intersects triangle
  708.     *t = D3DXVec3Dot( &edge2, &qvec );
  709.     FLOAT fInvDet = 1.0f / det;
  710.     *t *= fInvDet;
  711.     *u *= fInvDet;
  712.     *v *= fInvDet;
  713.  
  714.     return TRUE;
  715. }
  716.  
  717.  
  718.  
  719.